#include "graphicdatacommands.h"

#include <QtCore/QSet>

using namespace core;
using namespace swp;

AddGraphicItemCommand::AddGraphicItemCommand(
    GraphicData* data, IGraphicEditorItem* item) : QUndoCommand(),
        m_shouldDelete(false),
        m_data(data),
        m_item(item)
{
    setText(QObject::tr("Added %1 item").arg(item->name()));
}

AddGraphicItemCommand::~AddGraphicItemCommand()
{
    if (m_shouldDelete)
    {
        m_data->unregisterForResizeNotification(m_item);

        delete m_item;
    }
}

void AddGraphicItemCommand::undo()
{
    m_data->removeGraphicItem(m_item, true);
    m_shouldDelete = true;
}

void AddGraphicItemCommand::redo()
{
    if (m_item->parentDocumentData() != m_data)
    {
        m_data->addGraphicItem(m_item);
    }
    m_shouldDelete = false;
}

RemoveGraphicItemCommand::RemoveGraphicItemCommand(
    GraphicData* data, IGraphicEditorItem* item) : QUndoCommand(),
        m_shouldDelete(false),
        m_data(data),
        m_item(item),
        m_connections()
{
    setText(QObject::tr("Removed %1 item").arg(item->name()));
}

RemoveGraphicItemCommand::~RemoveGraphicItemCommand()
{
    if (m_shouldDelete)
    {
        m_data->unregisterForResizeNotification(m_item);

        delete m_item;
    }
}

void RemoveGraphicItemCommand::undo()
{
    if (m_item->parentDocumentData() != m_data)
    {
        m_data->addGraphicItem(m_item);
    }

    QSet<IEditorItem* > toBeNotified;

    foreach (const ConnectionData& data, m_connections)
    {
        QGraphicsItem* _connector = dynamic_cast<QGraphicsItem* >(
                data.Connector);

        if (_connector != 0 && data.Connector != m_item)
        {
            m_data->addGraphicItem(dynamic_cast<IGraphicEditorItem* >(
                data.Connector));
        }

        m_data->addConnection(data.From, data);
        m_data->addConnection(data.To, data);
        m_data->addConnection(data.Connector, data);

        m_data->addModelConnection(data);

        toBeNotified.insert(data.From);
        toBeNotified.insert(data.To);
        toBeNotified.insert(data.Connector);
    }

    foreach (IEditorItem* notifee, toBeNotified)
    {
        notifee->connectionsRefreshed();
    }

    m_shouldDelete = false;
}

void RemoveGraphicItemCommand::redo()
{
    m_connections = m_data->connections(m_item);

    QSet<IEditorItem* > toBeNotified;

    foreach (const ConnectionData& data, m_connections)
    {
        QGraphicsItem* _connector = dynamic_cast<QGraphicsItem* >(
                data.Connector);

        if (_connector != 0 && data.Connector != m_item)
        {
            m_data->removeGraphicItem(dynamic_cast<IGraphicEditorItem* >(
                data.Connector), true);

            IEditorItem* notifee = data.From == m_item ?
                data.To : data.From;
            toBeNotified.insert(notifee);
        }
        else if (_connector != 0)
        {
            toBeNotified.insert(data.From);
            toBeNotified.insert(data.To);
        }

        m_data->removeConnection(data.From, data);
        m_data->removeConnection(data.To, data);
        m_data->removeConnection(data.Connector, data);

        m_data->removeModelConnection(data);
    }

    foreach (IEditorItem* notifee, toBeNotified)
    {
        notifee->connectionsRefreshed();
    }

    m_data->removeGraphicItem(m_item, true);

    m_shouldDelete = true;
}

AddConnectionCommand::AddConnectionCommand(
    GraphicData* data, IGraphicEditorItem* connector,
    const ConnectionData& connection) : QUndoCommand(),
        m_shouldDelete(false),
        m_data(data),
        m_connector(connector),
        m_connection(connection)
{
    setText(QObject::tr("Added %1 connection").arg(connector->name()));
}

AddConnectionCommand::~AddConnectionCommand()
{
    if (m_shouldDelete)
    {
        delete m_connector;
    }
}

void AddConnectionCommand::undo()
{
    m_data->removeGraphicItem(m_connector, true);

    m_data->removeConnection(m_connection.From, m_connection);
    m_data->removeConnection(m_connection.To, m_connection);
    m_data->removeConnection(m_connection.Connector,
        m_connection);

    m_data->removeModelConnection(m_connection);

    m_connection.From->connectionsRefreshed();
    m_connection.To->connectionsRefreshed();

    m_shouldDelete = true;
}

void AddConnectionCommand::redo()
{
    if (m_connector->parentDocumentData() != m_data)
    {
        m_data->addGraphicItem(m_connector);
    }

    m_data->addConnection(m_connection.From, m_connection);
    m_data->addConnection(m_connection.To, m_connection);
    m_data->addConnection(m_connection.Connector,
        m_connection);

    m_data->addModelConnection(m_connection);

    m_connection.From->connectionsRefreshed();
    m_connection.To->connectionsRefreshed();
    m_connection.Connector->connectionsRefreshed();

    m_shouldDelete = false;
}

RemoveConnectionCommand::RemoveConnectionCommand(
    GraphicData* data, IGraphicEditorItem* connector,
    const ConnectionData& connection) : QUndoCommand(),
        m_shouldDelete(false),
        m_data(data),
        m_connector(connector),
        m_connection(connection)
{
    setText(QObject::tr("Removed %1 connection").arg(connector->name()));
}

RemoveConnectionCommand::~RemoveConnectionCommand()
{
    if (m_shouldDelete)
    {
        delete m_connector;
    }
}

void RemoveConnectionCommand::undo()
{
    if (m_connector->parentDocumentData() != m_data)
    {
        m_data->addGraphicItem(m_connector);
    }

    m_data->addConnection(m_connection.From, m_connection);
    m_data->addConnection(m_connection.To, m_connection);
    m_data->addConnection(m_connection.Connector,
        m_connection);

    m_data->addModelConnection(m_connection);

    m_connection.From->connectionsRefreshed();
    m_connection.To->connectionsRefreshed();
    m_connection.Connector->connectionsRefreshed();

    m_shouldDelete = false;
}

void RemoveConnectionCommand::redo()
{
    m_data->removeGraphicItem(m_connector, true);

    m_data->removeConnection(m_connection.From, m_connection);
    m_data->removeConnection(m_connection.To, m_connection);
    m_data->removeConnection(m_connection.Connector,
        m_connection);

    m_data->removeModelConnection(m_connection);

    m_connection.From->connectionsRefreshed();
    m_connection.To->connectionsRefreshed();

    m_shouldDelete = true;
}
